/*
 *
 * C++ MaJiang for 血流红中
 *
 * TuyooGame, 2021
 * zhouxin@tuyoogame.com
 *
 */
#ifndef __MJ_FANXING__
#define __MJ_FANXING__

#include <iostream>
#include <unordered_map>
#include <map>
#include <vector>
#include "mj_define.h"
#include "mj_tiles.h"
#include "mj_util.h"

using namespace std;

typedef enum mj_fanxing
{
    HUJIAOZHUANYI,
    
    // 翻倍(可叠加)
    GEN,
    GANGSHANGKAIHUA,
    GANGSHANGPAO,
    QIANGGANGHU,
    HAIDILAOYUE,
    MIAOSHOUHUICHUN,
    BIANZHANG,
    JUEZHANG,
    KANZHANG,
    MENQING,
    
    //基本翻型(不叠加)
    PINGHU,
    QINGYISE,
    TIANHU,
    DIHU,
    
    SHUANGANKE,
    LAOSHAOPEI,
    BUQIUREN,
    YITIAOLONG,
    SANANKE,
    DAYUWU,
    XIAOYUWU,
    QUANSHUANGKE,
    SANJIEGAO,
    SHIERJINCHAI,
    SIANKE,
    SIJIEGAO,
    QUANDAIWU,
    LVYISE,
    JIULIANBAODENG,
    YISESHUANGLONGHUI,
    LIANQIDUI,
    
    PENGPENGHU,
    JINGOUDIAO,
    SHIBALUOHAN,
    
    QIDUI,
    LONGQIDUI,
    SHUANGLONGQIDUI,
    SANLONGQIDUI,
    
    DAIYAOJIU,
    QUANYAOJIU,
    DUANYAOJIU,
    JIANGDUI,

    SHOUZHONGBAOYI,
    BAIWANDAN,
    ZHUOWUKUI,
    DANDIAO,
    YIBANGAO,
    LIULIANSHUN,
    SHUANGTONGKE,
    SUHU
} MJ_FANXING;

typedef struct mj_fanxing_info {
    const char *eng_name;
    const char *cn_name;
    uint32_t value;
} MJ_FANXING_DETAIL;

//一个完备的算番用到的数据集...
//各种算番函数参数统一是这个结构指针...
typedef struct mj_fx_info {
    MJ_TILE_TYPE que;  //缺门
    MJ_CPG_INFO  cpg;  //碰杠数据
    MJ_HU_TYPE hutype; //是否自摸等

    Tiles ti_hand;    //手牌(未加上nowtile)的Tiles实例
    Tiles ti_hand_now;//手牌加上nowtile后的Tiles实例
    Tiles ti_all;     //手牌加上nowtile和cpg的Tiles实例
    Tiles ti_all_gang4to3;     //手牌加上nowtile和cpg的Tiles实例,杠牌转换为3张

    int8_t now_tile;   //当前摸到的牌
    vector<uint8_t> tile_pool;
    
    //
    // update : fx方法返回uint64_t，第一个字节为返回值，其他字节放数据
    // 主要目的是这样可以方便的存在map里，参见mj.h里的MJ_FX_RET
    //
    //有些番型函数，需要返回数据后续处理，放到ret_data里
    //如暗刻，一般高等...
    //vector<uint8_t> ret_data; 
} MJ_FX_INFO;

//定义番型函数指针
typedef uint64_t (* FX_FUNC)(MJ_FX_INFO *m);
typedef uint64_t (* RM_FUNC)(MJ_FX_INFO *m, uint64_t r);

extern const unordered_map<MJ_FANXING, MJ_FANXING_DETAIL> fanPattern;
extern const unordered_map<MJ_FANXING, vector<MJ_FANXING>> fanPatternRelationMatrix;
extern const vector<MJ_FANXING> order_fan;
extern const unordered_map<MJ_FANXING, FX_FUNC> fxFuncMap;
extern const unordered_map<MJ_FANXING, RM_FUNC> fxRmFuncMap; 

//注意：对于3张碰牌，c4一定填0
void assignCPG(MJ_CPG *cpg, uint8_t tile,
               uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4, 
               int8_t seat, MJ_CPG_TYPE t, MJ_CPG_SUBTYPE st = CPG_NA);

bool assignMFI(MJ_FX_INFO *mfi, 
               vector<uint8_t> &hands, vector<uint8_t> &laizi, 
               uint8_t now_tile, MJ_TILE_TYPE que, MJ_CPG_INFO *cpg, 
               MJ_HU_TYPE ht=DIAN_PAO, 
               const vector<uint8_t> &pool = vector<uint8_t>());

bool hasHu(vector<uint8_t> ts, uint8_t t);
bool hasHu_bu(vector<uint8_t> ts, uint8_t bu_count, uint8_t bu_tile, uint8_t tile); 

uint64_t getFanGenCount(MJ_FX_INFO *m);
uint64_t hasAnKe(MJ_FX_INFO *m, uint8_t kes);
vector<vector<uint8_t>> getAllKeList(Tiles *ti, uint8_t nowtile, uint8_t kes, vector<uint8_t> &ankes);
vector<vector<uint8_t>> handListCom(vector<uint8_t> &hands);

//番型函数fx_*，参数统一为MJ_FX_INFO结构指针, 
//
//返回值0表示不符合
//返回1或者其他正数表示符合番型
//有些返回值表示一些特殊的数值意义
//例如fx_QiDui:非七对返回0,普通七对返回1,龙七对返回10，双龙返回20，三龙返回30
//
//有些番型函数，需要返回数据后续处理，放到MJ_FX_INFO的ret_data里
uint64_t fx_JueZhang(MJ_FX_INFO *m); 
uint64_t fx_QiDui(MJ_FX_INFO *m); 
uint64_t fx_YiTiaoLong(MJ_FX_INFO *m);
uint64_t fx_MenQing(MJ_FX_INFO *m);
uint64_t fx_QuanQiuRen(MJ_FX_INFO *m);
uint64_t fx_DuanYaoJiu(MJ_FX_INFO *m);
uint64_t fx_ShiBaLuoHan(MJ_FX_INFO *m);
uint64_t fx_ShiErJinChai(MJ_FX_INFO *m);
uint64_t fx_DuiDuiHu(MJ_FX_INFO *m);
uint64_t fx_PengPengHu(MJ_FX_INFO *m);
uint64_t fx_JinGouDiao(MJ_FX_INFO *m);
uint64_t fx_QingYiSe(MJ_FX_INFO *m);
uint64_t fx_258(MJ_FX_INFO *m);
uint64_t fx_LvYiSe(MJ_FX_INFO *m);
uint64_t fx_JiuLianBaoDeng(MJ_FX_INFO *m); 
uint64_t fx_LianQiDui(MJ_FX_INFO *m);
uint64_t fx_DaiYaoJiu(MJ_FX_INFO *m);
uint64_t fx_QuanYaoJiu(MJ_FX_INFO *m);
uint64_t fx_YiSeShuangLongHui(MJ_FX_INFO *m);
uint64_t fx_QuanShuangKe(MJ_FX_INFO *m);
uint64_t fx_QuanDaiWu(MJ_FX_INFO *m);
uint64_t fx_DaYuWu(MJ_FX_INFO *m);
uint64_t fx_XiaoYuWu(MJ_FX_INFO *m);
uint64_t fx_Bian(MJ_FX_INFO *m);
uint64_t fx_Kan(MJ_FX_INFO *m);
uint64_t fx_DanDiao(MJ_FX_INFO *m);
uint64_t fx_LaoShaoPei(MJ_FX_INFO *m);
uint64_t fx_ShuangTongKe(MJ_FX_INFO *m);
uint64_t fx_SanJieGao(MJ_FX_INFO *m);
uint64_t fx_SiJieGao(MJ_FX_INFO *m);
uint64_t fx_YiBanGao(MJ_FX_INFO *m);
uint64_t fx_LianLiu(MJ_FX_INFO *m);
uint64_t fx_BaiWanDan(MJ_FX_INFO *m);
uint64_t fx_JiangDui(MJ_FX_INFO *m);
uint64_t fx_ZhuoWuKui(MJ_FX_INFO *m);
uint64_t fx_DanDiaoHz(MJ_FX_INFO *m);
uint64_t fx_SiAnKe(MJ_FX_INFO *m);
uint64_t fx_SanAnKe(MJ_FX_INFO *m);
uint64_t fx_ShuangAnKe(MJ_FX_INFO *m);

uint64_t rm_WuKui(MJ_FX_INFO *m, uint64_t r);
uint64_t rm_LaoShao(MJ_FX_INFO *m, uint64_t r);
uint64_t rm_YiBanGao(MJ_FX_INFO *m, uint64_t r);
uint64_t rm_LianLiu(MJ_FX_INFO *m, uint64_t r);
uint64_t rm_DanDiao(MJ_FX_INFO *m, uint64_t r);

uint64_t rm_KeTiles(MJ_FX_INFO *m, vector<uint8_t> &ts);
uint64_t rm_TongKeTiles(MJ_FX_INFO *m, vector<uint8_t> &ts, uint64_t r);

//多个函数中用到，抽成一个辅助函数...
uint64_t _hand_nt(vector<uint8_t> & hand, uint8_t & now_tile, uint8_t tile); 

#endif
